home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / ms_sh21s.zip / SH210 / SRC / STDARGV.C < prev    next >
C/C++ Source or Header  |  1992-12-14  |  13KB  |  645 lines

  1. /* MS-DOS stdargv Function
  2.  *
  3.  * MS-DOS stdargv - Copyright (c) 1990,1,2 Data Logic Limited.
  4.  *
  5.  * This code is subject to the following copyright restrictions:
  6.  *
  7.  * 1.  Redistribution and use in source and binary forms are permitted
  8.  *     provided that the above copyright notice is duplicated in the
  9.  *     source form.
  10.  *
  11.  *    $Header: /usr/users/istewart/src/shell/sh2.1/RCS/stdargv.c,v 2.2 1992/12/14 11:12:37 istewart Exp $
  12.  *
  13.  *    $Log: stdargv.c,v $
  14.  *    Revision 2.2  1992/12/14  11:12:37  istewart
  15.  *    BETA 215 Fixes and 2.1 Release
  16.  *
  17.  *    Revision 2.1  1992/11/06  10:03:44  istewart
  18.  *    214 Beta test updates
  19.  *
  20.  *    Revision 2.0  1992/04/13  17:39:09  Ian_Stewartson
  21.  *    MS-Shell 2.0 Baseline release
  22.  *
  23.  *
  24.  *
  25.  * MODULE DEFINITION:
  26.  *
  27.  * This function expandes the command line parameters in a UNIX like manner.
  28.  * Wild character *?[] are allowed in file names. @filename causes command lines
  29.  * to be read from filename.  Strings between " or ' are not expanded.  All
  30.  * entries in the array are malloced.
  31.  *
  32.  * This function replaces the standard Microsoft C5.1 & C6.0 C Run-Time
  33.  * start up line processing function (_setargv in stdargv.obj).
  34.  *
  35.  * To get the OS2 version, compile with -DOS2
  36.  *
  37.  * Author:
  38.  *    Ian Stewartson
  39.  *    Data Logic, Queens House, Greenhill Way
  40.  *    Harrow, Middlesex  HA1 1YR, UK.
  41.  *    istewart@datlog.co.uk or ukc!datlog!istewart
  42.  */
  43.  
  44. #include <sys/types.h>            /* MS-DOS type definitions      */
  45. #include <sys/stat.h>            /* File status definitions    */
  46. #include <stdio.h>            /* Standard I/O delarations     */
  47. #include <stdlib.h>            /* Standard library functions   */
  48. #include <errno.h>            /* Error number declarations    */
  49. #ifdef OS2
  50. #define INCL_DOSSESMGR
  51. #define INCL_DOSMEMMGR
  52. #define INCL_DOSPROCESS
  53. #define INCL_WINSWITCHLIST
  54. #include <os2.h>            /* OS2 functions declarations   */
  55. #else
  56. #include <dos.h>            /* DOS functions declarations   */
  57. #include <bios.h>            /* BIOS functions declarations  */
  58. #endif
  59. #include <ctype.h>            /* Character type declarations  */
  60. #include <string.h>            /* String library functions     */
  61. #include <limits.h>            /* String library functions     */
  62. #include <fcntl.h>            /* File Control Declarations    */
  63. #include <dirent.h>            /* Direction I/O functions    */
  64. #include <unistd.h>
  65. #include <glob.h>            /* Globbing functions        */
  66.  
  67. /*
  68.  *  DATA DEFINITIONS:
  69.  */
  70.  
  71. #define MAX_LINE    160        /* Max line length        */
  72. #define S_ENTRY        sizeof (char *)
  73.  
  74. /*
  75.  *  DATA DECLARATIONS:
  76.  */
  77. #ifdef MSDOS
  78.  
  79. extern void    _setargv (void);
  80. static void    _Ex_CommandLine (char *);    /* Expand file        */
  81. static void    _Ex_ExpandIndirectFile (char *);
  82. static char    *_Ex_GetSpace (int, char *);    /* Get space        */
  83. static void    _Ex_AddArgument (char *);    /* Add argument        */
  84. static char    *_Ex_SkipWhiteSpace (char *);    /* Skip spaces        */
  85. static char    *_Ex_ConvertToUnixFormat (char *);
  86. static void    _Ex_ExpandField (char *);    /* Split file name    */
  87. static void    _Ex_FatalError (int, char *, char *);
  88. static char    *_Ex_ConvertEnvVariables (char *);
  89. static char    *_EX_OutOfMemory = "%s: %s\n";
  90.  
  91. extern char far    *_pgmptr;         /* Program name            */
  92. extern char    **__argv;         /* Current argument address    */
  93. extern int    __argc;         /* Current argument count    */
  94.  
  95. #ifdef OS2
  96. extern ushort    _aenvseg;        /* Environment seg        */
  97. extern ushort    _acmdln;        /* Command line offset        */
  98. #endif
  99.  
  100. /*
  101.  *  MODULE ABSTRACT: _setargv
  102.  *
  103.  *  UNIX like command line expansion
  104.  */
  105.  
  106. void    _setargv ()
  107. {
  108.     char far        *s;         /* Temporary string pointer        */
  109.  
  110. #  ifndef M_I86LM
  111.     char        buf[MAX_LINE];    /* Temporary space        */
  112. #  endif
  113.  
  114. #ifdef OS2
  115.     char far        *argvp = (char far *)((((long)_aenvseg) << 16));
  116.     ushort        off = _acmdln;
  117.     HSWITCH        hswitch;
  118.     SWCNTRL        swctl;
  119.     PIDINFO        PidInfo;
  120.     char        *cp;
  121.  
  122.     while (--off)
  123.     {
  124.     if (argvp[off - 1] == 0)
  125.          break;
  126.     }
  127.  
  128. /* Add program name */
  129.  
  130.     _pgmptr =  &argvp[off];
  131.  
  132.     if (argvp[_acmdln] == 0)
  133.     {
  134. #  ifndef M_I86LM
  135.     cp = buf;
  136.     s = _pgmptr;
  137.     while (*(cp++) = *(s++))
  138.         continue;
  139.  
  140.     _Ex_AddArgument (_Ex_ConvertToUnixFormat (buf));
  141. #  else
  142.     _Ex_AddArgument (_Ex_ConvertToUnixFormat (_pgmptr));
  143. #  endif
  144.     }
  145.  
  146.     else
  147.     {
  148.     argvp += _acmdln;
  149.  
  150. #  ifndef M_I86LM
  151.     cp = buf;
  152.     s = argvp;
  153.     while (*(cp++) = *(s++))
  154.         continue;
  155.  
  156.     off = strlen (buf);
  157.     _Ex_AddArgument (_Ex_ConvertToUnixFormat (buf));
  158.     argvp += off + 1;
  159.  
  160.     cp = buf;
  161.     s = argvp;
  162.     while (*(cp++) = *(s++))
  163.         continue;
  164.  
  165.     _Ex_CommandLine (buf);
  166. #  else
  167.     s = argvp;
  168.     _Ex_AddArgument (_Ex_ConvertToUnixFormat (argvp));
  169.  
  170.     argvp += strlen (argvp) + 1;
  171.  
  172. /*
  173.  * Add support in OS2 version for Eberhard Mattes EMX interface to commands.
  174.  */
  175.  
  176.     if ((*argvp) && (*(cp = argvp + strlen (argvp) + 1) == '~') &&
  177.         (strcmp (s, _Ex_ConvertToUnixFormat (cp + 1)) == 0))
  178.     {
  179.  
  180. /* Skip over the program name at string 2 to the start of the first
  181.  * argument at string 3
  182.  */
  183.  
  184.         argvp += strlen (argvp) + 1;
  185.         argvp += strlen (argvp) + 1;
  186.  
  187.         while (*argvp) 
  188.         {
  189.         if (*argvp == '~')
  190.             _Ex_AddArgument (argvp + 1);
  191.         
  192.         else
  193.             _Ex_AddArgument (argvp);
  194.  
  195.         argvp += strlen (argvp) + 1;
  196.         }
  197.     }
  198.  
  199.     else
  200.         _Ex_CommandLine (argvp);
  201.  
  202. #  endif
  203.  
  204. /* Set up the Window name.  Give up if it does not work.  */
  205.  
  206.     if (!DosGetPID (&PidInfo) &&
  207.         ((hswitch = WinQuerySwitchHandle (0, PidInfo.pid))) &&
  208.         (!WinQuerySwitchEntry (hswitch, &swctl)))
  209.     {
  210.         if ((cp = strrchr (__argv[0], '/')) == (char *)NULL)
  211.         cp = __argv[0];
  212.  
  213.         else
  214.             ++cp;
  215.  
  216.  
  217.         strncpy (swctl.szSwtitle, cp, MAXNAMEL);
  218.         swctl.szSwtitle[MAXNAMEL] = 0;
  219.  
  220.         if ((cp = strrchr (swctl.szSwtitle, '.')) != (char *)NULL)
  221.         *cp = 0;
  222.  
  223.         WinChangeSwitchEntry (hswitch, &swctl);
  224.     }
  225.     }
  226. #else
  227.                     /* Set up pointer to command line */
  228.     char far        *argvp = (char far *)((((long)_psp) << 16) + 0x081L);
  229.     unsigned int    envs = *(int far *)((((long)_psp) << 16) + 0x02cL);
  230.  
  231. /* Command line can be null or 0x0d terminated - convert to null */
  232.  
  233.     s = argvp;
  234.  
  235.     while (*s && (*s != 0x0d))
  236.     ++s;
  237.  
  238.     if (*s == 0x0d)
  239.     *s = 0;
  240.  
  241. /* Set up global parameters and expand */
  242.  
  243.     __argc = 0;
  244.  
  245. /* Get the program name */
  246.  
  247.     if ((_osmajor <= 2) || (envs == 0))
  248.     s = "unknown";
  249.  
  250. /* In the case of DOS 3+, we look in the environment space */
  251.  
  252.     else
  253.     {
  254.     s = (char far *)(((long)envs) << 16);
  255.  
  256.     while (*s)
  257.     {
  258.         while (*(s++) != 0)
  259.         continue;
  260.     }
  261.  
  262.     s += 3;
  263.     }
  264.  
  265. /* Add the program name        */
  266.  
  267.     _pgmptr = s;
  268.  
  269. #  ifndef M_I86LM
  270.     cp = buf;
  271.     while (*(cp++) = *(s++))
  272.     continue;
  273.  
  274.     _Ex_AddArgument (_Ex_ConvertToUnixFormat (buf));
  275.  
  276.     s  = argvp;
  277.     cp = buf;
  278.     while (*(cp++) = *(s++))
  279.     continue;
  280.  
  281.     _Ex_CommandLine (buf);
  282. #  else
  283.     _Ex_AddArgument (_Ex_ConvertToUnixFormat (s));
  284.     _Ex_CommandLine (argvp);
  285. #  endif
  286. #endif
  287.  
  288.     _Ex_AddArgument ((char *)NULL);
  289.     --__argc;
  290. }
  291.  
  292. /*
  293.  * Expand the DOS Command line
  294.  */
  295.  
  296. static void    _Ex_CommandLine (argvp)
  297. char        *argvp;            /* Line to expand            */
  298. {
  299.     char    *spos;            /* End of string pointer    */
  300.     char    *cpos;            /* Start of string pointer    */
  301.     char    *fn;            /* Extracted file name string    */
  302.  
  303. /* Search for next separator */
  304.  
  305.     spos = argvp;
  306.  
  307.     while (*(cpos = _Ex_SkipWhiteSpace (spos)))
  308.     {
  309.  
  310. /* Extract string argument */
  311.  
  312.     if ((*cpos == '"') || (*cpos == '\''))
  313.     {
  314.         spos = cpos + 1;
  315.  
  316.         do
  317.         {
  318.         if ((spos = strchr (spos, *cpos)) != NULL)
  319.         {
  320.             spos++;
  321.             if (spos[-2] != '\\')
  322.             break;
  323.         }
  324.  
  325.         else
  326.             spos = &spos[strlen (cpos)];
  327.  
  328.         } while (*spos);
  329.  
  330.         fn    = _Ex_GetSpace (spos - cpos - 2, cpos + 1);
  331.     }
  332.  
  333. /* Extract normal argument */
  334.  
  335.     else
  336.     {
  337.         spos = cpos;
  338.         while (!isspace (*spos) && *spos)
  339.         spos++;
  340.  
  341.         fn = _Ex_GetSpace (spos - cpos, cpos);
  342.     }
  343.  
  344. /* Process argument */
  345.  
  346.     if (*cpos != '\'')
  347.         fn = _Ex_ConvertEnvVariables (fn);
  348.  
  349.     switch (*cpos)
  350.     {
  351.         case '@':        /* Expand file                    */
  352.         _Ex_ExpandIndirectFile (fn);
  353.         break;
  354.  
  355.         case '"':        /* Expand string                */
  356.         case '\'':
  357.         _Ex_AddArgument (fn);
  358.         break;
  359.  
  360.         default:        /* Expand field                    */
  361.         _Ex_ExpandField (fn);
  362.     }
  363.  
  364.     free (fn);
  365.     }
  366. }
  367.  
  368. /* Expand an indirect file Argument */
  369.  
  370. static void    _Ex_ExpandIndirectFile (file)
  371. char        *file;        /* Expand file name                */
  372. {
  373.     FILE        *fp;        /* File descriptor                */
  374.     char    *EoLFound;    /* Pointer                */
  375.     int        c_maxlen = MAX_LINE;
  376.     char    *line;        /* Line buffer                    */
  377.     char    *eolp;
  378.  
  379. /* If file open fails, expand as a field */
  380.  
  381.     if ((fp = fopen (file + 1, "rt")) == NULL)
  382.     {
  383.     _Ex_ExpandField (file);
  384.     return;
  385.     }
  386.  
  387. /* Grab some memory for the line */
  388.  
  389.     if ((line = malloc (c_maxlen)) == (char *)NULL)
  390.     _Ex_FatalError (ENOMEM, _EX_OutOfMemory, (char *)NULL);
  391.  
  392. /* For each line in the file, remove EOF characters and add argument */
  393.  
  394.     while (fgets (line, c_maxlen, fp) != (char *)NULL)
  395.     {
  396.     EoLFound = strchr (line, '\n');
  397.     eolp = line;
  398.  
  399. /* Handle continuation characters */
  400.  
  401.     while (TRUE)
  402.     {
  403.  
  404. /* Check for a continuation character */
  405.  
  406.         if (((EoLFound = strchr (eolp, '\n')) != (char *)NULL) &&
  407.         (*(EoLFound - 1) == '\\'))
  408.         {
  409.         *(EoLFound - 1) = '\n';
  410.         *EoLFound = 0;
  411.         EoLFound = (char *)NULL;
  412.         }
  413.  
  414.         else if (EoLFound == (char *)NULL)
  415.         EoLFound = strchr (line, 0x1a);
  416.  
  417.         if (EoLFound != (char *)NULL)
  418.         break;
  419.  
  420. /* Find the end of the line */
  421.  
  422.         c_maxlen = strlen (line);
  423.  
  424. /* Get some more space */
  425.  
  426.         if ((line = realloc (line, c_maxlen + MAX_LINE)) == (char *)NULL)
  427.         _Ex_FatalError (ENOMEM, _EX_OutOfMemory, (char *)NULL);
  428.  
  429.         eolp = &line[c_maxlen];
  430.  
  431.         if (fgets (eolp, MAX_LINE, fp) == (char *)NULL)
  432.         break;
  433.     }
  434.  
  435. /* Terminate the line and add it to the argument list */
  436.  
  437.     if (EoLFound != (char *)NULL)
  438.         *EoLFound = 0;
  439.  
  440.     _Ex_AddArgument (line);
  441.     }
  442.  
  443.     if (ferror(fp))
  444.     _Ex_FatalError (errno, "%s: %s (%s)\n", file + 1);
  445.  
  446.     free (line);
  447.     fclose (fp);
  448.  
  449. /* Delete tempoary files */
  450.  
  451.     if (((line = strrchr (file + 1, '.')) != (char *)NULL) &&
  452.     (stricmp (line, ".tmp") == 0))
  453.     unlink (file + 1);            /* Delete it        */
  454. }
  455.  
  456. /* Get space for an argument name */
  457.  
  458. static char    *_Ex_GetSpace (length, in_s)
  459. int        length;            /* String length                */
  460. char        *in_s;                  /* String address        */
  461. {
  462.     char    *out_s;            /* Malloced space address       */
  463.  
  464.     if ((out_s = malloc (length + 1)) == (char *)NULL)
  465.     _Ex_FatalError (ENOMEM, _EX_OutOfMemory, (char *)NULL);
  466.  
  467. /* Copy string for specified length */
  468.  
  469.     strncpy (out_s, in_s, length);
  470.     out_s[length] = 0;
  471.  
  472.     return (out_s);
  473. }
  474.  
  475. /* Append an argument to the array */
  476.  
  477. static void    _Ex_AddArgument (Argument)
  478. char        *Argument;            /* Argument to add        */
  479. {
  480.     if (__argc == 0)
  481.     __argv = (char **)malloc (50 * S_ENTRY);
  482.  
  483.     else if ((__argc % 50) == 0)
  484.     __argv = (char **)realloc (__argv, (__argc + 50) * S_ENTRY);
  485.  
  486.     if (__argv == (char **)NULL)
  487.     _Ex_FatalError (ENOMEM, _EX_OutOfMemory, (char *)NULL);
  488.  
  489.     if (Argument == (char *)NULL)
  490.     __argv[__argc++] = (char *)NULL;
  491.  
  492.     else
  493.     __argv[__argc++] = _Ex_GetSpace (strlen (Argument), Argument);
  494. }
  495.  
  496. /*  Skip over spaces */
  497.  
  498. static char    *_Ex_SkipWhiteSpace (a)
  499. char        *a;            /* String start address        */
  500. {
  501.     while (isspace(*a))
  502.         a++;
  503.  
  504.     return (a);
  505. }
  506.  
  507. /* Convert name to Unix format */
  508.  
  509. static char    *_Ex_ConvertToUnixFormat (a)
  510. char        *a;
  511. {
  512.     char    *sp = a;
  513.  
  514.     while ((a = strchr (a, '\\')) != (char *)NULL)
  515.     *(a++) = '/';
  516.  
  517. #ifndef OS2
  518.     return strlwr (sp);
  519. #else
  520.     if (!IsHPFSFileSystem (sp))
  521.     strlwr (sp);
  522.  
  523.     return sp;
  524. #endif
  525.  
  526. }
  527.  
  528. /* Find the location of meta-characters.  If no meta, add the argument and
  529.  * return NULL.  If meta characters, return position of end of directory
  530.  * name.  If not multiple directories, return -1
  531.  */
  532.  
  533. static void    _Ex_ExpandField (file)
  534. char        *file;
  535. {
  536.     int        i = 0;
  537.     glob_t    gp;
  538.  
  539.     if (strpbrk (file, "?*[]\\") == (char *)NULL)
  540.     {
  541.     _Ex_AddArgument (file);
  542.     return;
  543.     }
  544.  
  545.     if (glob (file, GLOB_NOCHECK, (int (*)())NULL , &gp))
  546.     _Ex_FatalError (ENOMEM, _EX_OutOfMemory, (char *)NULL);
  547.  
  548.     i = 0;
  549.  
  550.     while (i < gp.gl_pathc)
  551.     _Ex_AddArgument (gp.gl_pathv[i++]);
  552.  
  553.     globfree (&gp);
  554. }
  555.  
  556. /* Fatal errors */
  557.  
  558. static void    _Ex_FatalError (ecode, format, para)
  559. int        ecode;
  560. char        *format;
  561. char        *para;
  562. {
  563.     fprintf (stderr, format, "stdargv", strerror (ecode), para);
  564.     exit (1);
  565. }
  566.  
  567. /* Process Environment - note that field is a malloc'ed field */
  568.  
  569. static char    *_Ex_ConvertEnvVariables (field)
  570. char        *field;
  571. {
  572.     char    *sp, *cp, *np, *ep;
  573.     char    save;
  574.     int        b_flag;
  575.  
  576.     sp = field;
  577.  
  578. /* Replace any $ strings */
  579.  
  580.     while ((sp = strchr (sp, '$')) != (char *)NULL)
  581.     {
  582.  
  583. /* If ${...}, find the terminating } */
  584.  
  585.     if (*(cp = ++sp) == '{')
  586.     {
  587.         b_flag = 1;
  588.         ++cp;
  589.  
  590.         while (*cp && (*cp != '}'))
  591.         cp++;
  592.     }
  593.  
  594. /* Else must be $..., find the terminating non-alphanumeric */
  595.  
  596.     else
  597.     {
  598.         b_flag = 0;
  599.  
  600.         while (isalnum (*cp))
  601.         cp++;
  602.     }
  603.  
  604. /* Grab the environment variable */
  605.  
  606.     if (cp == sp)
  607.         continue;
  608.  
  609. /* Get its value */
  610.  
  611.     save = *cp;
  612.     *cp = 0;
  613.     ep = getenv (sp + b_flag);
  614.     *cp = save;
  615.  
  616.     if (ep != (char *)NULL)
  617.     {
  618.         np = _Ex_GetSpace (strlen(field) - (cp - sp) + strlen (ep) - 1, field);
  619.         strcpy (&np[sp - field - 1], ep);
  620.         free (field);
  621.         strcpy ((sp = &np[strlen(np)]), cp + b_flag);
  622.         field = np;
  623.     }
  624.     }
  625.  
  626.     return field;
  627. }
  628. #endif
  629.  
  630. /*
  631.  * Test main program
  632.  */
  633.  
  634. #ifdef TEST
  635. int    main (int argc, char **argv)
  636. {
  637.     int        i;
  638.  
  639.     for (i = 0; i < argc; i++)
  640.     printf ("Arg %d = |%s|\n", i, argv[i]);
  641.     
  642.     return 0;
  643. }
  644. #endif
  645.